/* * Copyright (C) 2007-2008 Esmertec AG. Copyright (C) 2007-2008 The Android Open * Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package info.guardianproject.otr.app.im.app; import info.guardianproject.otr.app.im.IChatSession; import info.guardianproject.otr.app.im.IChatSessionManager; import info.guardianproject.otr.app.im.IImConnection; import info.guardianproject.otr.app.im.R; import info.guardianproject.otr.app.im.app.ContactListFilterView.ContactListListener; import info.guardianproject.otr.app.im.plugin.BrandingResourceIDs; import info.guardianproject.otr.app.im.provider.Imps; import info.guardianproject.otr.app.im.service.ImServiceConstants; import info.guardianproject.util.LogCleaner; import java.util.Observable; import java.util.Observer; import android.app.Activity; import android.app.SearchManager; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Message; import android.os.RemoteException; import android.support.v4.widget.SearchViewCompat; import android.util.AttributeSet; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MenuItem.OnMenuItemClickListener; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.CursorAdapter; import android.widget.ExpandableListView.ExpandableListContextMenuInfo; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; public class ContactListActivity extends ThemeableActivity implements View.OnCreateContextMenuListener, ContactListListener { private static final int MENU_START_CONVERSATION = Menu.FIRST; private static final int MENU_VIEW_PROFILE = Menu.FIRST + 1; private static final int MENU_BLOCK_CONTACT = Menu.FIRST + 2; private static final int MENU_DELETE_CONTACT = Menu.FIRST + 3; private static final int MENU_END_CONVERSATION = Menu.FIRST + 4; private static final String FILTER_STATE_KEY = "Filtering"; ImApp mApp; long mProviderId; long mAccountId; IImConnection mConn; ContactListView mContactListView; ContactListFilterView mFilterView; SimpleAlertHandler mHandler; ContextMenuHandler mContextMenuHandler; boolean mIsFiltering = true; Imps.ProviderSettings.QueryMap mGlobalSettingMap; boolean mDestroyed; View mSearchView; @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); LayoutInflater inflate = getLayoutInflater(); mContactListView = (ContactListView) inflate.inflate(R.layout.contact_list_view, null); mFilterView = (ContactListFilterView) getLayoutInflater().inflate( R.layout.contact_list_filter_view, null); mFilterView.setListener(this); mFilterView.getListView().setOnCreateContextMenuListener(this); getSherlock().getActionBar().setHomeButtonEnabled(true); getSherlock().getActionBar().setDisplayHomeAsUpEnabled(true); Intent intent = getIntent(); mAccountId = intent.getLongExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, -1); if (mAccountId == -1) { finish(); return; } mApp = (ImApp)getApplication(); } private void initAccount () { ContentResolver cr = getContentResolver(); Cursor c = cr.query(ContentUris.withAppendedId(Imps.Account.CONTENT_URI, mAccountId), null, null, null, null); if (c == null) { //finish(); return; } if (!c.moveToFirst()) { // c.close(); //finish(); return; } mProviderId = c.getLong(c.getColumnIndexOrThrow(Imps.Account.PROVIDER)); mHandler = new MyHandler(this); String username = c.getString(c.getColumnIndexOrThrow(Imps.Account.USERNAME)); //c.close(); // BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); // setTitle(brandingRes.getString(BrandingResourceIDs.STRING_BUDDY_LIST_TITLE, username)); setTitle(username); // getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, // brandingRes.getDrawable(BrandingResourceIDs.DRAWABLE_LOGO)); mGlobalSettingMap = new Imps.ProviderSettings.QueryMap(getContentResolver(), true, null); mApp.callWhenServiceConnected(mHandler, new Runnable() { public void run() { if (!mDestroyed) { mApp.dismissNotifications(mProviderId); mConn = mApp.getConnection(mProviderId); if (mConn == null) { clearConnectionStatus(); try { mConn = mApp.createConnection(mProviderId, mAccountId); } catch (RemoteException e) { Log.e(ImApp.LOG_TAG, "The connection cannot be created"); // finish(); } } // mFilterView.mPresenceView.setConnection(mConn); mFilterView.setConnection(mConn); mContactListView.setConnection(mConn); mContactListView.setHideOfflineContacts(mGlobalSettingMap .getHideOfflineContacts()); } } }); mContextMenuHandler = new ContextMenuHandler(); mContactListView.getListView().setOnCreateContextMenuListener(this); mGlobalSettingMap.addObserver(new Observer() { public void update(Observable observed, Object updateData) { if (!mDestroyed) { mContactListView.setHideOfflineContacts(mGlobalSettingMap .getHideOfflineContacts()); } } }); showFilterView(); } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getSupportMenuInflater(); inflater.inflate(R.menu.contact_list_menu, menu); mSearchView = SearchViewCompat.newSearchView(this); if (mSearchView != null) { MenuItem item = menu.add("Search") .setIcon(android.R.drawable.ic_menu_search) .setActionView(mSearchView); item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW); SearchViewCompat.setOnQueryTextListener(mSearchView, new SearchViewCompat.OnQueryTextListenerCompat() { @Override public boolean onQueryTextChange(String newText) { mFilterView.doFilter(newText); return true; } @Override public boolean onQueryTextSubmit(String query) { mFilterView.doFilter(query); return true; } }); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { //TODO make sure this works case R.id.menu_invite_user: Intent i = new Intent(ContactListActivity.this, AddContactActivity.class); i.putExtra(ImServiceConstants.EXTRA_INTENT_PROVIDER_ID, mProviderId); i.putExtra(ImServiceConstants.EXTRA_INTENT_ACCOUNT_ID, mAccountId); i.putExtra(ImServiceConstants.EXTRA_INTENT_LIST_NAME, mContactListView.getSelectedContactList()); startActivity(i); return true; case android.R.id.home: case R.id.menu_view_accounts: startActivity(new Intent(getBaseContext(), ChooseAccountActivity.class)); // finish(); return true; case R.id.menu_settings: Intent sintent = new Intent(this, SettingActivity.class); startActivity(sintent); return true; case R.id.menu_view_groups: if (mIsFiltering) showContactListView(); else showFilterView(); return true; } return super.onOptionsItemSelected(item); } Intent getEditAccountIntent(boolean isSignedIn) { Uri uri = ContentUris.withAppendedId(Imps.Provider.CONTENT_URI, mProviderId); @SuppressWarnings("deprecation") Cursor cursor = managedQuery(uri, new String[] { Imps.Provider.CATEGORY }, null, null, null); cursor.moveToFirst(); Intent intent = new Intent(Intent.ACTION_EDIT, ContentUris.withAppendedId( Imps.Account.CONTENT_URI, mAccountId)); intent.addCategory(cursor.getString(0)); // cursor.close(); intent.putExtra("isSignedIn", isSignedIn); return intent; } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(FILTER_STATE_KEY, mIsFiltering); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { boolean isFiltering = savedInstanceState.getBoolean(FILTER_STATE_KEY); if (isFiltering) { showFilterView(); } super.onRestoreInstanceState(savedInstanceState); } @Override public boolean dispatchKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); boolean handled = false; if (!mIsFiltering) { handled = mFilterView.dispatchKeyEvent(event); if (!handled && (KeyEvent.KEYCODE_BACK == keyCode) && (KeyEvent.ACTION_DOWN == event.getAction())) { showFilterView(); handled = true; } } else { handled = mContactListView.dispatchKeyEvent(event); if (!handled && KeyEvent.KEYCODE_SEARCH == keyCode && (KeyEvent.ACTION_DOWN == event.getAction())) { InputMethodManager inputMgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMgr.toggleSoftInput(0, 0); if (!mIsFiltering) showFilterView(); onSearchRequested(); } else if (!handled && isReadable(keyCode, event) && (KeyEvent.ACTION_DOWN == event.getAction())) { if (!mIsFiltering) showFilterView(); handled = mFilterView.dispatchKeyEvent(event); } } if (!handled) { handled = super.dispatchKeyEvent(event); } return handled; } @Override protected void onNewIntent(Intent intent) { // The user has probably entered a URL into "Go" String action = intent.getAction(); if (Intent.ACTION_SEARCH.equals(action)) { if (mIsFiltering) { String filterText = intent.getStringExtra(SearchManager.QUERY); mFilterView.doFilter(filterText); } } } private static boolean isReadable(int keyCode, KeyEvent event) { if (KeyEvent.isModifierKey(keyCode) || event.isSystem()) { return false; } switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_DPAD_DOWN: case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_ENTER: return false; } return true; } private void showFilterView() { if (mGlobalSettingMap == null) return; Uri uri = mGlobalSettingMap.getHideOfflineContacts() ? Imps.Contacts.CONTENT_URI_ONLINE_CONTACTS_BY : Imps.Contacts.CONTENT_URI_CONTACTS_BY; uri = ContentUris.withAppendedId(uri, mProviderId); uri = ContentUris.withAppendedId(uri, mAccountId); mFilterView.doFilter(uri, null); setContentView(mFilterView); mFilterView.requestFocus(); mIsFiltering = true; } void showContactListView() { setContentView(mContactListView); mContactListView.requestFocus(); mContactListView.invalidate(); mIsFiltering = false; } @Override protected void onPause() { super.onPause(); mApp.unregisterForConnEvents(mHandler); } @Override protected void onResume() { super.onResume(); mApp = (ImApp)getApplication(); mApp.startImServiceIfNeed(); mApp.setAppTheme(this); initAccount (); mApp.registerForConnEvents(mHandler); mContactListView.setAutoRefreshContacts(true); // Get the intent, verify the action and get the query showFilterView(); Intent intent = getIntent(); if (intent.getAction() != null && Intent.ACTION_SEARCH.equals(intent.getAction())) { if (mIsFiltering) { String filterText = intent.getStringExtra(SearchManager.QUERY); mFilterView.doFilter(filterText); } } } @Override protected void onDestroy() { mDestroyed = true; // set connection to null to unregister listeners. mContactListView.setConnection(null); mFilterView.setConnection(null); if (mGlobalSettingMap != null) { mGlobalSettingMap.close(); } super.onDestroy(); } static void log(String msg) { Log.v(ImApp.LOG_TAG, "<ContactListActivity> " + msg); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { boolean chatSelected = false; boolean contactSelected = false; Cursor contactCursor; if (mIsFiltering) { AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; mContextMenuHandler.mPosition = info.position; contactSelected = true; contactCursor = mFilterView.getContactAtPosition(info.position); } else { ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo; mContextMenuHandler.mPosition = info.packedPosition; contactSelected = mContactListView.isContactAtPosition(info.packedPosition); contactCursor = mContactListView.getContactAtPosition(info.packedPosition); } boolean allowBlock = true; if (contactCursor != null) { //XXX HACK: Yahoo! doesn't allow to block a friend. We can only block a temporary contact. ProviderDef provider = mApp.getProvider(mProviderId); if (Imps.ProviderNames.YAHOO.equals(provider.mName)) { int type = contactCursor.getInt(contactCursor .getColumnIndexOrThrow(Imps.Contacts.TYPE)); allowBlock = (type == Imps.Contacts.TYPE_TEMPORARY); } int nickNameIndex = contactCursor.getColumnIndexOrThrow(Imps.Contacts.NICKNAME); menu.setHeaderTitle(contactCursor.getString(nickNameIndex)); } BrandingResources brandingRes = mApp.getBrandingResource(mProviderId); String menu_end_conversation = brandingRes .getString(BrandingResourceIDs.STRING_MENU_END_CHAT); String menu_view_profile = brandingRes .getString(BrandingResourceIDs.STRING_MENU_VIEW_PROFILE); String menu_block_contact = brandingRes .getString(BrandingResourceIDs.STRING_MENU_BLOCK_CONTACT); String menu_start_conversation = brandingRes .getString(BrandingResourceIDs.STRING_MENU_START_CHAT); String menu_delete_contact = brandingRes .getString(BrandingResourceIDs.STRING_MENU_DELETE_CONTACT); if (chatSelected) { menu.add(0, MENU_END_CONVERSATION, 0, menu_end_conversation) .setOnMenuItemClickListener(mContextMenuHandler); menu.add(0, MENU_VIEW_PROFILE, 0, menu_view_profile) .setIcon(R.drawable.ic_menu_my_profile) .setOnMenuItemClickListener(mContextMenuHandler); if (allowBlock) { menu.add(0, MENU_BLOCK_CONTACT, 0, menu_block_contact) .setOnMenuItemClickListener(mContextMenuHandler); } } else if (contactSelected) { menu.add(0, MENU_START_CONVERSATION, 0, menu_start_conversation) .setOnMenuItemClickListener(mContextMenuHandler); menu.add(0, MENU_VIEW_PROFILE, 0, menu_view_profile) .setIcon(R.drawable.ic_menu_view_profile) .setOnMenuItemClickListener(mContextMenuHandler); if (allowBlock) { menu.add(0, MENU_BLOCK_CONTACT, 0, menu_block_contact) .setOnMenuItemClickListener(mContextMenuHandler); } menu.add(0, MENU_DELETE_CONTACT, 0, menu_delete_contact) .setIcon(android.R.drawable.ic_menu_delete) .setOnMenuItemClickListener(mContextMenuHandler); } // contactCursor.close(); } void clearConnectionStatus() { ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(3); values.put(Imps.AccountStatus.ACCOUNT, mAccountId); values.put(Imps.AccountStatus.PRESENCE_STATUS, Imps.Presence.OFFLINE); values.put(Imps.AccountStatus.CONNECTION_STATUS, Imps.ConnectionStatus.OFFLINE); // insert on the "account_status" uri actually replaces the existing value cr.insert(Imps.AccountStatus.CONTENT_URI, values); } final class ContextMenuHandler implements MenuItem.OnMenuItemClickListener, OnMenuItemClickListener { long mPosition; public boolean onMenuItemClick(MenuItem item) { Cursor c; if (mIsFiltering) { c = mFilterView.getContactAtPosition((int) mPosition); } else { c = mContactListView.getContactAtPosition(mPosition); } switch (item.getItemId()) { case MENU_START_CONVERSATION: mContactListView.startChat(c); break; case MENU_VIEW_PROFILE: mContactListView.viewContactPresence(c); break; case MENU_BLOCK_CONTACT: mContactListView.blockContact(c); break; case MENU_DELETE_CONTACT: mContactListView.removeContact(c); break; case MENU_END_CONVERSATION: mContactListView.endChat(c); break; default: return false; } if (mIsFiltering) { showContactListView(); } return true; } @Override public boolean onMenuItemClick(android.view.MenuItem item) { Cursor c; if (mIsFiltering) { c = mFilterView.getContactAtPosition((int) mPosition); } else { c = mContactListView.getContactAtPosition(mPosition); } switch (item.getItemId()) { case MENU_START_CONVERSATION: mContactListView.startChat(c); break; case MENU_VIEW_PROFILE: mContactListView.viewContactPresence(c); break; case MENU_BLOCK_CONTACT: mContactListView.blockContact(c); break; case MENU_DELETE_CONTACT: mContactListView.removeContact(c); break; case MENU_END_CONVERSATION: mContactListView.endChat(c); break; default: return false; } if (mIsFiltering) { showContactListView(); } return true; } } final class MyHandler extends SimpleAlertHandler { public MyHandler(Activity activity) { super(activity); } @Override public void handleMessage(Message msg) { if (msg.what == ImApp.EVENT_CONNECTION_DISCONNECTED) { if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { log("Handle event connection disconnected."); } promptDisconnectedEvent(msg); long providerId = ((long) msg.arg1 << 32) | msg.arg2; if (providerId == mProviderId) { if (Log.isLoggable(ImApp.LOG_TAG, Log.DEBUG)) { log("Current connection disconnected, finish"); } startActivity(getEditAccountIntent(false)); // finish(); } return; } super.handleMessage(msg); } } public boolean onClose() { return false; } protected boolean isAlwaysExpanded() { return false; } private static final String[] PROVIDER_PROJECTION = { Imps.Provider._ID, Imps.Provider.NAME, Imps.Provider.FULLNAME, Imps.Provider.CATEGORY, Imps.Provider.ACTIVE_ACCOUNT_ID, Imps.Provider.ACTIVE_ACCOUNT_USERNAME, Imps.Provider.ACTIVE_ACCOUNT_PW, Imps.Provider.ACTIVE_ACCOUNT_LOCKED, Imps.Provider.ACTIVE_ACCOUNT_KEEP_SIGNED_IN, Imps.Provider.ACCOUNT_PRESENCE_STATUS, Imps.Provider.ACCOUNT_CONNECTION_STATUS, }; static final int PROVIDER_ID_COLUMN = 0; static final int PROVIDER_NAME_COLUMN = 1; static final int PROVIDER_FULLNAME_COLUMN = 2; static final int PROVIDER_CATEGORY_COLUMN = 3; static final int ACTIVE_ACCOUNT_ID_COLUMN = 4; static final int ACTIVE_ACCOUNT_USERNAME_COLUMN = 5; static final int ACTIVE_ACCOUNT_PW_COLUMN = 6; static final int ACTIVE_ACCOUNT_LOCKED = 7; static final int ACTIVE_ACCOUNT_KEEP_SIGNED_IN = 8; static final int ACCOUNT_PRESENCE_STATUS = 9; static final int ACCOUNT_CONNECTION_STATUS = 10; @Override public void startChat(Cursor c) { if (c != null) { long id = c.getLong(c.getColumnIndexOrThrow(Imps.Contacts._ID)); String username = c.getString(c.getColumnIndexOrThrow(Imps.Contacts.USERNAME)); try { IChatSessionManager manager = mConn.getChatSessionManager(); IChatSession session = manager.getChatSession(username); if (session == null) { manager.createChatSession(username); } Uri data = ContentUris.withAppendedId(Imps.Chats.CONTENT_URI, id); Intent i = new Intent(Intent.ACTION_VIEW, data); i.addCategory(ImApp.IMPS_CATEGORY); startActivity(i); // mScreen.finish(); //mContactListView.setAutoRefreshContacts(false); } catch (RemoteException e) { mHandler.showServiceErrorAlert(e.getLocalizedMessage()); LogCleaner.error(ImApp.LOG_TAG, "remote error",e); } } } public void showProfile (Cursor c){} }